package com.example.pacs.utils;

import org.dcm4che3.data.Attributes;
import org.dcm4che3.data.Tag;
import org.dcm4che3.data.UID;
import org.dcm4che3.io.DicomInputStream;
import org.dcm4che3.net.*;
import org.dcm4che3.net.pdu.AAssociateRQ;
import org.dcm4che3.net.pdu.PresentationContext;
import org.dcm4che3.util.SafeClose;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 测试发送dcm文件到开源pacs服务器
 */
@Component
public class SendDicomFileUtils {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final Connection remote = new Connection();

    private final ApplicationEntity applicationEntity = new ApplicationEntity("STORESCU");

    private final AAssociateRQ aAssociateRQ = new AAssociateRQ();

    private Association association;

    private ExecutorService executorService;

    /**
     * 初始化设备信息
     *
     * @author liuhaiyang
     * @date 2021/04/15 16:22
     * @return  insert语句
     */
    public void initDevice() {
        // 创建一个设备
        Device device = new Device("storescu");
        // 创建一个连接
        Connection connection = new Connection();
        // 给设备添加一个连接
        device.addConnection(connection);
        // 给设备添加一个应用
        device.addApplicationEntity(applicationEntity);
        // 给设备添加一个线程池
        executorService = Executors.newSingleThreadExecutor();
        device.setExecutor(executorService);
        remote.setTlsProtocols(connection.getTlsProtocols());
        remote.setTlsCipherSuites(connection.getTlsCipherSuites());
        applicationEntity.addConnection(connection);
        aAssociateRQ.addPresentationContext(new PresentationContext(1, UID.VerificationSOPClass, UID.ImplicitVRLittleEndian));
    }

    /**
     * 初始化服务端SCP,设置应用名称,支持服务和编码方式
     */
    public void initServerInfo(String calledAETitle, String remoteHost, int remotePort) {
        // 设置SCU的应用名称
        applicationEntity.setAETitle("client1");
        // 设置SCP的应用名称
        aAssociateRQ.setCalledAET(calledAETitle);
        remote.setHostname(remoteHost);
        remote.setPort(remotePort);
    }

    /**
     * 发送文件到pacs服务器
     */
    public void sendDicomFile(String filePath) throws IOException, InterruptedException {
        File file = new File(filePath);
        if (!file.exists()) {
            return;
        }
        DicomInputStream dicomInputStream = null;
        try {
            dicomInputStream = new DicomInputStream(file);
            dicomInputStream.setIncludeBulkData(DicomInputStream.IncludeBulkData.NO);
            Attributes attributes = dicomInputStream.readFileMetaInformation();
            String abstractSyntax = attributes.getString(Tag.MediaStorageSOPClassUID);
            String instance = attributes.getString(Tag.MediaStorageSOPInstanceUID);
            String transferSyntax = attributes.getString(Tag.TransferSyntaxUID);
            aAssociateRQ.addPresentationContext(new PresentationContext(aAssociateRQ.getNumberOfPresentationContexts() + 2, abstractSyntax, transferSyntax));
            association = applicationEntity.connect(remote, aAssociateRQ);
            long position = dicomInputStream.getPosition();
            FileInputStream fileInputStream = new FileInputStream(file);
            fileInputStream.skip(position);
            InputStreamDataWriter inputStreamDataWriter = new InputStreamDataWriter(fileInputStream);
            association.cstore(abstractSyntax, instance, Priority.NORMAL, inputStreamDataWriter, transferSyntax, new DimseRSPHandler(association.nextMessageID()));
        } catch (Exception e) {
            logger.error("e" + e.getMessage(), e);
        }finally {
            close();
            SafeClose.close(dicomInputStream);
        }
    }

    public void close() throws IOException, InterruptedException {
        if (executorService != null) {
            executorService.shutdown();
        }
        if (association != null && association.isReadyForDataTransfer()) {
            association.release();
            association.waitForSocketClose();
        }
    }

    public void sendFile(String calledAETitle, String filePath, String remoteHost, int remotePort) {
        initDevice();
        initServerInfo(calledAETitle, remoteHost, remotePort);
        try {
            sendDicomFile(filePath);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
